package Concorrentes;

import java.util.ArrayList;

public class Controlador {
	
	// Objetos e Threads dos trechos
	private static ArrayList<Trecho> trechos;
	private static ArrayList<Thread> Ttrechos;
	
	// Objetos e Threads dos carros
	private static ArrayList<Carro> carros;
	private static ArrayList<Thread> Tcarros;

	// Objetos e Threads dos guardas
	private static ArrayList<Guarda> guardas;
	private static ArrayList<Thread> Tguardas;
	
	// Objetos e Threads dos pedestres
	private static ArrayList<Pedestre> pedestres;
	private static ArrayList<Thread> Tpedestres;
	
	// Objeto e Thread da Balsa
	private static Balsa balsa;
	private static Thread Tbalsa;
	
	private static int numeroCarros;
	private static int numeroGuardas;
	private static int numeroPedestres;
	private static final int numeroTrechos = 10;
	private static final double tamanhoTrecho = 10.0;
	private static final int carPool = 200;
	private static final int pedestrePool = 50;
	
	private static boolean iniciouSimulacao = false;
	private static boolean terminouSimulacao = false;
	
	private static final int velocidadeMaxima = 45;
	
	public static int getVelocidadeMaxima(){
		return velocidadeMaxima;
	}
	
	public static void setTerminouSimulacao(boolean termino){
		if(terminouSimulacao == false && termino == true)
			System.out.println("Simulação terminada");
		terminouSimulacao = termino;
	}
	
	public static boolean getTerminouSimulacao(){
		return terminouSimulacao;
	}
	
	public static void addCarro(Carro carro){
		carros.add(carro);
	}
	
	public static void addTCarro(Thread Tcarro){
		Tcarros.add(Tcarro);
	}
	
	public static void addGuarda(Guarda guarda){
		guardas.add(guarda);
	}
	
	public static void addTGuarda(Thread Tguarda){
		Tguardas.add(Tguarda);
	}
	
	public static void addTrecho(Trecho trecho){
		trechos.add(trecho);
	}
	
	public static void addTtrecho(Thread Ttrecho){
		Ttrechos.add(Ttrecho);
	}
	
	public static boolean fimDaSimulacao(){
		return (getTerminouSimulacao() == true);
	}
	
	public static void carroQuerEntrar(Carro carro, int trecho, int direcao){
		if((trecho == 0 && direcao == 1) || (trecho == 1 && direcao == 0)){
			filaDaBalsa(carro, direcao);
		} else {
			trechos.get(trecho).addCarro(carro);
		}
	}
	
	public static void carroSaiuDaBalsa(Carro carro){
		if(carro.getDirecao() == 0)
			trechos.get(1).addCarro(carro);
		else
			trechos.get(0).addCarro(carro);
	}

	private static void filaDaBalsa(Carro carro, int direcao) {
			balsa.addCarroNaFila(carro, direcao);
	}

	public static void acordaCarro(int carro) {
		carros.get(carro).acorda();
	}
	
	public static void acordaTrecho(int trecho){
		trechos.get(trecho%numeroTrechos).acorda();
	}
	
	public static void paraCarroAcostamento(int carro) {
		carros.get(carro).setNoAcostamento(true);	
	}
	
	public static boolean isCarroNoAcostamento(int carro){
		return (carros.get(carro).isNoAcostamento());
	}
	
	public static void liberaCarroAcostamento(int carro){
		carros.get(carro).saiDoAcostamento();
	}

	public static double getTamanhoTrecho(){
		return tamanhoTrecho;
	}
	
	public static int getNumeroCarros(){
		return numeroCarros;
	}
	
	public static int getNumeroGuardas(){
		return numeroGuardas;
	}
	
	public static int getNumeroTrechos(){
		return numeroTrechos;
	}
	
	public static void setNumeroCarros(int nCarros){
		numeroCarros = nCarros;		
	}
	
	public static void setNumeroGuardas(int nGuardas){
		numeroGuardas = nGuardas;		
	}
	
	public static ArrayList<Carro> getCarros() {
		return carros;
	}
	
	public static boolean temCarrosSubindoSerra(){
		for(Trecho trecho : trechos){
			if(trecho.temCarrosNoTrecho()){
				return true;
			}
		}
		return false;
	}
	
	public static void iniciaSimulacao(){
		// Comeca a simulacao
		if(!iniciouSimulacao){
			iniciouSimulacao = true;
			
			Controlador.inicializaThreads();
			
			// Acorda primeiro trecho e dá início a simulação
			trechos.get(0).acorda();
		}
	}
	
	public static void init(){
		trechos = new ArrayList<Trecho>();
		Ttrechos = new ArrayList<Thread>();
		
		carros = new ArrayList<Carro>();
		Tcarros = new ArrayList<Thread>();
		
		guardas = new ArrayList<Guarda>();
		Tguardas = new ArrayList<Thread>();
		
		pedestres = new ArrayList<Pedestre>();
		Tpedestres = new ArrayList<Thread>();
	}

	public static void inicializaThreads() {
		// Inicializa todas as Threads
		for(Thread Ttrecho : Ttrechos){	
			Ttrecho.start();
		}

		for(Thread Tguarda : Tguardas){
			Tguarda.start();
		}
		
		// Inicializa apenas o numero inicial de pedestres
		for(int i = 0; i < Controlador.getNumeroPedestres(); i++){
			Tpedestres.get(i).start();
		}
		
		// Inicializa apenas o numero inicial de carros
		for(int i = 0; i < Controlador.getNumeroCarros(); i++){
			Tcarros.get(i).start();
		}
		Tbalsa.start();
	}
	
	public static void adicionaUmCarro(){
		if(!iniciouSimulacao){
			if(Controlador.getNumeroCarros() < carPool){
				Controlador.setNumeroCarros(Controlador.getNumeroCarros() + 1);
			}
		} else {
			if(!fimDaSimulacao() && Controlador.getNumeroCarros() < carPool){
				Tcarros.get(Controlador.getNumeroCarros()).start();
				Controlador.setNumeroCarros(Controlador.getNumeroCarros() + 1);
			}
		}
	}
	
	public static void adicionaUmPedestre(){
		if(!iniciouSimulacao){
			if(Controlador.getNumeroPedestres() < pedestrePool){
				Controlador.setNumeroPedestres(Controlador.getNumeroPedestres() + 1);
			}
		} else {
			if(!fimDaSimulacao() && Controlador.getNumeroPedestres() < pedestrePool){
				Tpedestres.get(Controlador.getNumeroPedestres()).start();
				Controlador.setNumeroPedestres(Controlador.getNumeroPedestres() + 1);
			}
		}
	}

	public static int getCarPool() {
		return carPool;
	}

	public static void addBalsa(Balsa balsa2) {
		balsa = balsa2;
	}

	public static void addTBalsa(Thread Tbalsa2) {
		Tbalsa = Tbalsa2;
	}

	public static void addPedestreNoTrecho(int trecho) {
		trechos.get(trecho).addPedestres(1);
		
	}

	public static void removePedestreNoTrecho(int trecho) {
		trechos.get(trecho).removePedestres(1);
	}

	public static int getNumeroPedestres() {
		return numeroPedestres;
	}

	public static void addPedestre(Pedestre pedestre) {
		pedestres.add(pedestre);
	}
	
	public static void addTPedestre(Thread Tpedestre){
		Tpedestres.add(Tpedestre);
	}

	public static void setNumeroPedestres(int i) {
		numeroPedestres = i;
	}

	public static boolean temPedestreTrecho(int trecho) {
		return trechos.get(trecho).temPedestreNoTrecho();
	}

	public static int getPedestrePool() {
		return pedestrePool;
	}
}
